/*
 * formulation.c
 *
 *  Created on: 30/12/2011
 *      Author: marcio
 */

#include "formulation.h"

CPXENVptr** env;//ambiente do cplex
CPXLPptr** prob;//problema inteiro
long** varToEdge;//mapeamento de variavel para aresta
long**** edgeToVar;//mapeamento de aresta para variavel
long** var;//numero de variaveis;

extern long k;//o k da coloração
extern long* va;//a ordem dos vertices

int init(){
	setAdjMatrix(getSharedGraph());
	var = malloc(sizeof(long)*nverts());
	long i,l,j;

	setAdjMatrix(getSharedGraph());
	var = 0;
	long i,l,j,m;

	//alocação de memoria pra edgeVar
	edgeToVar = malloc(sizeof(long***)*nverts());
	for(i = 0; i < nverts(); i++){
		var[va[i]] = malloc(sizeof(long)*k);
		edgeToVar[va[i]] = malloc(sizeof(long**)*nverts());
		for(j = i; j < nverts(); j++){
			edgeToVar[va[i]][va[j]] = malloc(sizeof(long*)*k);
			for(l = 0; l < k; l++){
				edgeToVar[va[i]][va[j]][l] = malloc(sizeof(long)*k);
				var[va[i]][l] = 0;
			}
		}
	}

	//alocação de memoria para verToedge
	varToEdge = malloc(sizeof(long*)*nverts()*nverts()*k);
	for(i = 0; i < nverts()*nverts()*k; i++){
		varToEdge[i] = malloc(sizeof(long)*4);
	}

	for(i = 0; i < nverts(); i++){
		for(l = 0; l < k; l++){
			for(m = 0; m < k; m++){
				edgeToVar[va[i]][va[i]][l][m] = var[va[i]][l];
				varToEdge[var][0] = va[i];
				varToEdge[var][1] = va[i];
				varToEdge[var][2] = l;
				varToEdge[var][3] = l;
			}
			var[va[i]][l]++;
		}
		for(j = i+1; j < nverts(); j++){
			if(hasEdge(va[i], va[j]) || i == j){
				for(l = 0; l < k; l++){
					for(m = 0; m < k; m++){
						edgeToVar[va[i]][va[j]][l][m] = var[va[i]][l];
						varToEdge[var][0] = va[i];
						varToEdge[var][1] = va[j];
						varToEdge[var][2] = l;
						varToEdge[var][3] = m;
						var[va[i]][l]++;
					}
					//printf("var = %d é referente a %d %d %d \n", var, va[i], va[j], l);
				}
			}
		}
	}

	env = malloc(sizeof(CPXENVptr*)*nverts());
	prob = malloc(sizeof(CPXLPptr*)*nverts());
	for(i = 0; i < k; i++){
		env[i] = malloc(sizeof(CPXENVptr*)*k);
		prob[i] = malloc(sizeof(CPXLPptr*)*k);
	}

	for(i = 0; i < nverts(); i++){
		for(j = 0; j < k; j++){
			env[va[i]][j] = CPXopenCPLEX(&status);
			prob[va[i]][j] = CPXcreateprob(env, &status, "Formulação de k-col!!!");
			double obj[nverts()*k];
			double lb[nverts()*k];
			double ub[nverts()*k];
			char type[nverts()*k];
			for(l = 0;l < nverts()*k; l++){
				obj[l] = 1.0;
				lb[l] = 0.0;
				ub[l] = 1.0;
				type[l] = 'C';
			}
			//cria as variavies
			CPXnewcols(env[va[i]][j], prob[va[i]][j], var[va[i]][j], obj, lb, ub, type, NULL);
			//defini o sentindo da função objetivo
			CPXchgobjsen(env[va[i]][j], prob[va[i]][j], CPX_MIN);
			CPXchgprobtype(env[va[i]][j], prob[va[i]][j], CPXPROB_LP);
		}
	}

}

/*adiciona restrição na anti-vizinhança de v referente a u e w*/
int addEdgeConstrain(long v, long u, long w){
	setAdjMatrix(getSharedGraph());
	int l;
	for(l = 0; l < k; l++){
		double rhs[1] = {0.0};//lado direito da restriçao
		char sense[1] = {'L'};// sentido da restriçao
		int rmatbeg[3] = {0,3};
		int rmatind[3];
		rmatind[0] = edgeToVar[v][u][l];
		rmatind[1] = edgeToVar[v][w][l];
		rmatind[2] = edgeToVar[v][v][l];
		double rmatval[3] = {1.0, 1.0, -1.0};
		CPXaddrows(env[v], prob[v], 0, 1, 3, rhs, sense, rmatbeg, rmatind, rmatval, NULL, NULL);
	}
	return 0;
}

/*adiciona restrição de aresta a u e v*/
int addIndConstrain(long v, long u){
	setAdjMatrix(getSharedGraph());
	int l;
	for(l = 0; l < k; l++){
		double rhs[1] = {0.0};//lado direito da restriçao
		char sense[1] = {'L'};// sentido da restriçao
		int rmatbeg[2] = {0,2};
		int rmatind[2];
		rmatind[0] = edgeToVar[v][u][l];
		rmatind[1] = edgeToVar[v][v][l];
		double rmatval[2] = { 1.0, -1.0};
		CPXaddrows(env[v], prob[v], 0, 1, 2, rhs, sense, rmatbeg, rmatind, rmatval, NULL, NULL);
	}
	return 0;
}

/*Adiciona restrição de Cover referente a v*/
int changeObjCoef(double* mu){
	int indices[nverts()];
	for(i = 0; i < nverts(); i++)indice[i] = i;

	double coefs[nverts()];
	int i, j,l;

	for(i = 0; i < nverts(); i++){
		for(j = i; j < nverts(); j++){
			if(hasEdge(va[i], va[j])){
				for(l = 0; l < k; l++){
					if(i == j)coefs[edgeToVar[va[i]][va[i]][l]] = 1 - mu[va[i]];
					coefs[edgeToVar[va[i]][va[j]][l]] = (-1)*mu[va[j]];
				}
			}
		}
		CPXchgobj(env[va[i]], prob[va[i]], var[va[i]], indice, coefs);
	}
	return 0;
}


double solveSingleLP(int v){
	double value;
	CPXgetobjval(env[va[v]],prob[va[v]], &value);
	return value;
}


int getX(double*** x){
	double y[nverts()];
	int i , j;
	for(i = 0; i < nverts(); i++){
		CPXgetx (env[va[i]], prob[va[i]], y, 0, var[va[i]]-1);
		for(j = 0; j < var[va[i]]; j++){
			x[varToEdge[va[i]][j][0]][varToEdge[va[i]][j][0]][varToEdge[va[i]][j][0]] = y[j];
		}
	}
}
